#ifndef PDD_H_
#define PDD_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stddef.h>
#include <stdint.h>
#include <poll.h>
#include <semaphore.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include "config.h"
#include "sockets.h"
#include "log.h"


#define TAMSECTOR 512
#define FINARCHIVO 0xfffffff
#define NOMBRELARGO 0x0F
#define ENTRADADIR 0x10
#define ENTRADAARC 0x20
#define ENTRADABORRADA 0x2E
#define HANDSHAKE 0
#define Retorno_OK 0
#define pathCfg "/config.cfg"
#define DESCENDENTE 0x87
#define ASCENDENTE 0x88


/*Archivo Config */
typedef struct {
	char *modoInicio;
	char *algoritmo;
	char *pathConsola;
	char *nombreVD;
	char *dirIPpfs;
	char *dirIPpraid;
	int32_t puertoPFS;
	int32_t puertoPRAID;
	int32_t logActivado;
	int32_t cantPedidos;
	int32_t idDisco;
	int32_t c;
	int32_t h;
	int32_t s;
	int32_t tiempoLectura;
	int32_t tiempoEscritura;
	int32_t rpm;
	int32_t tiempoSaltoPistas;
	int32_t cantMSync;
	int32_t cantMmap;
}t_config;

char *setearCfgPPD(char *token);
int32_t stringAInt32 (char *pToken);
t_config abrirArchivoConfig();



/* Funciones PPD */

void inicializarVariables();
void procesoConsola();
int32_t iniciarConsola ();
void cerrarConsola(int32_t signal);

uint32_t calcularDireccion(uint32_t unSector);
int32_t abrirMapearArchivoDisco ();
int32_t cerrarArchivoMapeado();

int32_t handshakePRAID();
int32_t handshakePFS (int32_t socketPFS);

int32_t leerSector(uint32_t iNumeroSector,void *vDatosAretornar);
int32_t escribirSector(uint32_t iNumeroSector,char *vDatosAEscribir);



/* Listas PRAID */
struct nodoPRAID
{
	t_NIPC paquete;
	struct nodoPRAID *next;
};

typedef struct nodoPRAID t_nodoPRAID;

typedef struct{
	t_nodoPRAID *head;
}t_listaPRAID;

t_listaPRAID *crearListaPRAID();
void sacarDeLaListaPRAID (t_nodoPRAID ** nodo);
void agregarEnLaListaPRAID(int32_t posicion, t_NIPC paqueteNuevo);


/* Listas PFS */
struct nodoPFS
{
	t_NIPC paquete;
	int32_t socket;
	struct nodoPFS *next;
};

typedef struct nodoPFS t_nodoPFS;

typedef struct{
	t_nodoPFS *head;
}t_listaPFS;

t_listaPFS *crearListaPFS();
void sacarDeLaListaPFS (t_nodoPFS **nodo);
void agregarEnLaListaPFS (int32_t posicion, t_NIPC paquete, int32_t socketFD);



/* Planificacion */

typedef struct {
	uint32_t C;
	uint32_t H;
	uint32_t S;
} t_CHS;

typedef struct
{
	t_CHS posActual;
	pthread_mutex_t bloqueaCabezal;
	int32_t sentido;
}tCabezal;

void pasarACHS(uint32_t sector, t_CHS *sectorTransformado);
void pasarAuint (t_CHS sectorCHS, uint32_t *sectorLogico);
uint32_t numeroPista (uint32_t sector);
void loguearTipoPedido(t_NIPC paquete);
void actualizarCabezal(int32_t nroSector);


/* C-LOOK */
int32_t planificarPedidoPRAID (t_NIPC paquete);
int32_t planificarPedidoPFS (t_NIPC paquete, int32_t socketFD);
void insertarDespuesDeCabezalPRAID (t_NIPC paqueteNuevo);
void insertarAntesDeCabezalPRAID (t_NIPC paqueteNuevo);
void insertarDespuesDeCabezalPFS (t_NIPC paqueteNuevo, int32_t socketFD);
void insertarAntesDeCabezalPFS (t_NIPC paqueteNuevo, int32_t socketFD);


/* Funciones Consola */
void switchConsola(t_NIPC paquete);
void parsearSectores(char *cadenaAseparar, int32_t *cantidad, int32_t **sectores);
void info(t_NIPC paqueteRecibido);
void clean (t_NIPC paquete);
void trace (t_NIPC paquete);
void salir();



/* Conexion PFS */
void setearFD(struct pollfd *descriptores,int32_t nroSocket);
void recibirPedidosPRAID(struct pollfd *descriptoresLectura);
void recibirPedidosPFS();


/* Thread Responder Pedidos */
int32_t responderPedidos(t_NIPC *paqueteAenviar, t_NIPC *paqueteRecibido);
void responderPedidosRAID ();
void responderPedidosPFS ();
void informacionPlanificacion(uint32_t nroSector, char **trace);


#endif /* PDD_H_ */
